[AWS CDK] API Gateway REST API の「ゲートウェイレスポンス」を設定して、API レベルのエラー発生時に CORS エラーを発生させないようにする
こんにちは、CX 事業本部 Delivery 部の若槻です。
Amazon API Gateway REST API では ゲートウェイレスポンス を設定することにより、API レベルのエラー発生時に任意のレスポンスを返すことができます。
今回は、AWS CDK で REST API の「ゲートウェイレスポンス」を設定して、API レベルのエラー発生時に CORS エラーを発生させないようにしてみました。
既定では API レベルのエラー発生時は CORS エラーが発生する
REST API のゲートウェイの設定メニューは次のようになっています。既定ではどのエラーでもレスポンスヘッダーが設定されていません。
よって、例えば Authorizer が設定された API に対して、認証されていない状態で Web 画面からリクエストを送信すると、レスポンスに CORS 許可用のヘッダーは設定されないため、次のようにブラウザ側で CORS エラーが発生します。
CORS エラーが発生することにより、クライアント側でのエラーハンドリングやデバッグが難しくなります。
ゲートウェイレスポンスを設定する
API レベルのエラー発生時に任意のレスポンスを返すには、ゲートウェイレスポンスを設定します。ここではすべてのエラーに対して、CORS 許可用ヘッダーを設定するようにしてみます。
import { aws_lambda, aws_lambda_nodejs, aws_apigateway, aws_cognito, Duration, } from "aws-cdk-lib"; import { Construct } from "constructs"; interface ApiConstructProps { cognitoUserPool: aws_cognito.UserPool; } export class ApiConstruct extends Construct { constructor(scope: Construct, id: string, props: ApiConstructProps) { super(scope, id); const { cognitoUserPool } = props; const restApiFunc = new aws_lambda_nodejs.NodejsFunction( this, "RestApiFunc", { architecture: aws_lambda.Architecture.ARM_64, entry: "../server/src/lambda/handlers/api-gateway/rest-api-router.ts", tracing: aws_lambda.Tracing.ACTIVE, }, ); const cognitoUserPoolsAuthorizer = new aws_apigateway.CognitoUserPoolsAuthorizer( this, "CognitoUserPoolsAuthorizer", { cognitoUserPools: [cognitoUserPool], }, ); const restApi = new aws_apigateway.LambdaRestApi(this, "RestApi", { handler: restApiFunc, defaultCorsPreflightOptions: { allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, allowMethods: aws_apigateway.Cors.ALL_METHODS, allowHeaders: aws_apigateway.Cors.DEFAULT_HEADERS, maxAge: Duration.minutes(5), }, deployOptions: { stageName: "v1", tracingEnabled: true, }, defaultMethodOptions: { authorizer: cognitoUserPoolsAuthorizer }, }); restApi.addGatewayResponse("Default4xx", { type: aws_apigateway.ResponseType.DEFAULT_4XX, responseHeaders: { "Access-Control-Allow-Origin": "'*'", "Access-Control-Allow-Headers": "'*'", "Access-Control-Allow-Methods": "'*'", }, }); restApi.addGatewayResponse("Default5xx", { type: aws_apigateway.ResponseType.DEFAULT_5XX, responseHeaders: { "Access-Control-Allow-Origin": "'*'", "Access-Control-Allow-Headers": "'*'", "Access-Control-Allow-Methods": "'*'", }, }); } }
API Construct に対して addGatewayResponse
でゲートウェイレスポンスを設定しています。DEFAULT_4XX
および DEFAULT_5XX
に対して設定することにより、すべてのエラーに対して CORS 許可用ヘッダーを設定することができます。必要に応じてヘッダー値を絞ってください。
CDK デプロイすると、すべてのエラーに対してレスポンスヘッダーが設定されます。
改めて認証されていない状態で Web 画面からリクエストを送信すると、今度は CORS エラーは発生せず 401 (Inauthorized)
エラーのみ表示されるようになりました。
おまけ
前述の動作確認でも使用した CORS エラーを簡易的に確認する Web 画面のソースコードです。ただし任意のリクエストヘッダーを指定可能とするなど改良の余地はあります。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>CORS Checker</title> </head> <body> <h1>CORS Checker</h1> <form> <label for="endpoint">API Gateway Endpoint:</label> <input type="text" id="endpoint" name="endpoint" /> <button type="submit">Check CORS</button> </form> <div id="result"></div> <script> const form = document.querySelector("form"); const resultDiv = document.querySelector("#result"); form.addEventListener("submit", async (event) => { event.preventDefault(); const endpoint = document.querySelector("#endpoint").value; try { const response = await fetch(endpoint); const corsHeaders = response.headers.get("access-control-allow-origin"); resultDiv.textContent = `CORS headers: ${corsHeaders}`; } catch (error) { resultDiv.textContent = "Error occurred while fetching CORS headers"; } }); </script> </body> </html>
おわりに
AWS CDK で REST API の「ゲートウェイレスポンス」を設定して、API レベルのエラー発生時に CORS エラーを発生させないようにしてみました。
できれば目にはしたくない CORS エラー、簡単に抑制することができるのでぜひお試しください。
以上